// ==ClosureCompiler==
// @output_file_name goog.ext.min.js
// @compilation_level SIMPLE_OPTIMIZATIONS
// @use_closure_library true
// ==/ClosureCompiler==
goog.provide('goog.dom.forms.Validator');

goog.require('goog.dom');
goog.require('goog.dom.classes');
goog.require('goog.dom.forms');
goog.require('goog.style');
goog.require('goog.array');
goog.require('goog.object');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.Timer');
goog.require('goog.net.XhrIo');

fs.require('goog.ext');

goog.dom.forms.Validator = {
/**
 * правила для проверки полей формы
 *
 * @var {Object}
 */
  rules_: {
    required: function(v){return!!v;},
    number  : function(v){return/^[\+-]?\d+(\.\d+(e[\+-]\d+)?)?$/i.test(v);},
    integer : function(v){return/^\d+$/.test(v);},
    login   : function(v){return/^[\w-]+$/.test(v);},
    email   : function(v){return/^[a-z\d!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-z\d!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-z\d](?:[a-z\d-]*[a-z\d])?\.)+[a-z\d](?:[a-z\d-]*[a-z\d])?$/i.test(v);},
    phone   : function(v){return/^(((\+?(\d{1,4}|\d-\d{1,3})[\s-]?)?(\(\d{3}\)|\d{3}))?(\d{3}([\s-]?\d{2}){2}|\d{2}[\s-]?\d{3}[\s-]?\d{2}|(\d{2}[\s-]?){2}\d{3})|((\+?\d{1,3}[\s-]?)?(\(\d{4}\)|\d{4}))?(\d{2}[\s-]?){2}\d{2}|((\+?\d{1,3}[\s-]?)?(\(\d{5}\)|\d{5}))?(\d([\s-]?\d{2}){2}|\d{2}[\s-]?\d[\s-]?\d{2}|(\d{2}[\s-]?){2}\d))$/.test(v);}
  },
/**
 * сообщения об ошибках
 *
 * @var {Object}
 */
  messages: {
    required: 'Поле необходимо заполнить',
    number  : 'Некорректное число',
    integer : 'Некорректный номер',
    login   : 'Логин должен содержать только буквы латинского алфавита, цифры, знаки "_" и "-"',
    email   : 'E-mail указан неверно',
    phone   : 'Некорректный номер телефона'
  },
/**
 * Скрыть сообщение об ошибке в поле при изменении значения
 *
 * @var {Function}
 */
  hideOnKey_: function()
  {
    /** @var {Element} field */
    var field = this;
    /** @var {String} v */
    var v = field.value;
    goog.Timer.callOnce(function(){(field.value==v)||goog.dom.forms.Validator.hideError(field);}, 1);
  },
/**
 * Добавить правило
 *
 * @param {String} name
 * @param {Function} rule
 * @return void
 */
  addRule: function(name,rule){name&&goog.isFunction(rule)&&(this.rules_[name]=rule);},
/**
 * Вывести сообщение об ошибке в поле
 *
 * @param {Node} field
 * @param {String} msg
 * @return void
 */
  showError: function(field, msg)
  {
    if (field = goog.dom.$(field))
    {
      if (msg)
        if (field.errorElement)
        {
          goog.dom.setTextContent(field.errorElement, msg);
          goog.dom.classes.add(field.errorElement, 'error');
          goog.style.setStyle(field.errorElement, 'display', 'block');
        }
        else
          goog.dom.insertSiblingAfter(field.errorElement = goog.dom.createDom('div', {'class': 'error'}, msg), field);
      else
        this.hideError(field);
      goog.dom.classes.add(field, 'error');
      goog.events.listen(field, goog.events.EventType.KEYPRESS, this.hideOnKey_);
    }
  },
/**
 * Скрыть сообщение об ошибке в поле
 *
 * @param {Node} field
 * @return void
 */
  hideError: function(field)
  {
    if (field = goog.dom.$(field))
    {
      field.errorElement && goog.style.setStyle(field.errorElement, 'display', 'none');
      goog.dom.classes.remove(field, 'error');
      goog.events.unlisten(field, goog.events.EventType.KEYPRESS, this.hideOnKey_);
    }
  }
};

/**
 * Инициализировать проверку полей перед оправкой формы
 *
 * @param {Element} form
 * @param {Object} o
 * @return void
 */
  goog.dom.forms.validate = function(form, o)
  {
    goog.isObject(o) || (o = {});
    goog.isObject(o.rules) || (o.rules = {});
    goog.isObject(o.messages) || (o.messages = {});

    goog.events.listen(form, goog.events.EventType.SUBMIT, function()
    {
      var rules  = {};
      var fields = {};
      var errors = {};
      goog.array.forEach(
        goog.dom.findNodes(this, function(node)
        {
          goog.dom.forms.Validator.hideError(node);
          node.name && (rules[node.name] = []) && goog.object.forEach(goog.dom.forms.Validator.rules_, function(f, rule)
          {
            (goog.dom.classes.has(node, rule) || (o.rules[node.name] && (goog.isArray(o.rules[node.name]) ? 0 <= goog.array.indexOf(o.rules[node.name], rule) : rule.iequals(o.rules[node.name])))) && rules[node.name].push(rule);
          });
          return rules[node.name] && rules[node.name].length && (fields[node.name] = node);
        }),
        function(field)
        {
          goog.array.forEach(rules[field.name], function(rule)
          {
            errors[field.name] ||
            (goog.dom.forms.Validator.rules_[rule](field.value) ? goog.object.remove(fields, field.name) : errors[field.name] = o.messages[field.name] && o.messages[field.name][rule] ? o.messages[field.name][rule] : goog.dom.forms.Validator.messages[rule] || '');
          });
        }
      );
      if (goog.object.isEmpty(errors))
      {
        if (goog.isFunction(o.submit))
          goog.net.XhrIo.sendForm(form, o.submit);
        else
          return true;
      }
      else
      {
        goog.object.forEach(errors, function(msg,name){goog.dom.forms.Validator.showError(fields[name],msg);});
        goog.dom.forms.focusAndSelect(goog.object.getAnyValue(fields));
      }
      return false;
    });
  }
